# frozen_string_literal: true

module EE
  module Gitlab
    module BackgroundMigration
      # rubocop: disable Style/Documentation
      module BackfillMissingVulnerabilityDismissalDetails
        extend ActiveSupport::Concern
        extend ::Gitlab::Utils::Override

        DISMISSED_STATE = 2

        prepended do
          scope_to ->(relation) { relation.where(state: DISMISSED_STATE, dismissed_at: nil, dismissed_by_id: nil) }
          operation_name :backfill_missing_vulnerability_dismissal_details
        end

        class StateTransition < ::ApplicationRecord
          self.table_name = 'vulnerability_state_transitions'
        end

        class Vulnerability < ::ApplicationRecord
          self.table_name = 'vulnerabilities'
        end

        override :perform
        def perform
          each_sub_batch do |sub_batch|
            state_transitions = StateTransition.where(vulnerability_id: sub_batch.select(:id),
              to_state: DISMISSED_STATE).where(
                <<~SQL
                  NOT EXISTS (SELECT 1 FROM "vulnerability_state_transitions" AS "vst"
                          WHERE "vst"."created_at" > "vulnerability_state_transitions"."created_at"
                          AND "vst"."to_state" = #{DISMISSED_STATE}
                          AND "vst"."vulnerability_id" = "vulnerability_state_transitions"."vulnerability_id")
                SQL
              )

            sub_batch.each do |vulnerability|
              vst = state_transitions.find { |transition| transition.vulnerability_id == vulnerability.id }

              if vst.nil?
                log_missing_transition(vulnerability)
                next
              end

              vulnerability.update!(dismissed_at: vst.created_at, dismissed_by_id: vst.author_id)
              log_success(vulnerability)
            end
          end
        end
        # rubocop: enable Style/Documentation

        private

        def log_success(vulnerability)
          ::Gitlab::BackgroundMigration::Logger.info(
            migrator: self.class.name,
            message: 'Vulnerability dismissal information restored.',
            vulnerability_id: vulnerability.id
          )
        end

        def log_missing_transition(vulnerability)
          ::Gitlab::BackgroundMigration::Logger.warn(
            migrator: self.class.name,
            message: 'Invalid dismissed vulnerability lacks a state transition to restore from.',
            vulnerability_id: vulnerability.id
          )
        end
      end
    end
  end
end
